<?php

/*
  Aurus CMS - free OOP CMS
  Copyright (C) 2010  Nestor Yanchuk

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
if (! defined('ROOT'))
	die();

/**
 * One of system core classes
 * 
 * @package Aurus
 * @author Kvis
 * @copyright 2010
 * @version 1.0
 * @access public
 */
class Aurus implements Core {
	
	/**
	 * Return an instance of class
	 *
	 * @return Aurus
	 */
	public static function getInstance() {
		return Factory::get(__CLASS__);
	}
	
	/**
	 * Масив повідомленнь і помилок скрипту які будуть виведені користувачеві в шаблон info.tpl
	 *
	 * @var array
	 */
	private $errors = array ();
	private $info = array ();
	
	/**
	 * Внутрішній буфер, все що потрібно вивести функцією echo
	 * @var string
	 */
	private $echo = '';
	/**
	 * @ignore
	 */
	private $clientJS = '';
	/**
	 * @ignore
	 */
	private $includedEditors = array ();
	/**
	 * @ignore
	 */
	private $includeJS = array ();
	/**
	 * @ignore
	 */
	private $editors = array ();
	/**
	 * @ignore
	 */
	private $cronJobs = array ();
	/**
	 * @ignore
	 */
	private $adminConfigPages = array ();
	/**
	 * @ignore
	 */
	private $keyWords = array ();
	private $metadata = '';
	private $title = '';
	private $CONTENT = '';
	
	/**
	 * Деструктор класу, запускається при завершенні роботи скрипту.Викликає приватну функцію виконання крону
	 *
	 */
	public function __destruct() {
		$this->cron();
	}
	
	/**
	 * Перетворення зовнішього посилання у внутрішнє
	 *
	 * @param string $url
	 * @return string
	 */
	public static function externalToInternalUrl($url) {
		if (getHost($url) == getHost(LINK_ROOT)) {
			return $url;
		}
		return LINK_ROOT . 'go.php?' . rawurlencode($url);
	}
	
	/**
	 * Функція повертає назву шаблону який потрібно завантажити
	 *
	 * @return string назва шаблону
	 */
	public function getTemplateToLoad() {
		return Config::get('template');
	}
	
	/**
	 * Функція повертає початковий тег тегу <form> (наприклад. <form method="..." >)
	 *
	 * @param string $method - метод передачі даних у формі - post або get
	 * @param string $action - адреса сторінки якій будуть передані дані, якщо не вказано - поточна сторінка
	 * @param boolean $datatransfer - логічна змінна, якщо "так" - по формі можна передати файл, "ні" - звичайна форма
	 * @return string
	 */
	public function form_start($method = 'post', $action = null, $datatransfer = false) {
		$e = '';
		if (! $action) {
			$LR = parse_url(LINK_ROOT);
			$action = $LR['scheme'] . '://' . $LR['host'] . $_SERVER['REQUEST_URI'];
		}
		if ($datatransfer) {
			$e = ' enctype="multipart/form-data"';
		}
		
		$action = str_replace('&amp;', '&', $action);
		$action = str_replace('&', '&amp;', $action);
		return '<form method="' . $method . '"' . $e . ' action="' . $action . '" >';
	}
	
	/**
	 * Встановлення повідомленнь користувачеві, заноситься в масив $this->errors
	 *
	 * @param string $error
	 */
	public function setError($err) {
		$this->errors[] = $err;
	}
	
	public function setInfo($info) {
		$this->info[] = $info;
	}
	
	/**
	 * Функція встановлює заголовок сторінки
	 *
	 * @param string $title - заголовок сторінки
	 */
	public function setTitle($title) {
		$title = htmlspecialchars_decode($title);
		$saparator = ' - ';
		if ($this->title == '') {
			$this->title = Config::get('title');
		}
		$this->title .= $saparator . $title;
	}
	
	/**
	 * Переадресація користувача на сторінку $loc
	 *
	 * @param string $loc - адреса сторінки
	 */
	public static function location($loc = '') {
		if (! $loc) {
			if (isset($_SERVER['HTTP_REFERER'])) {
				$loc = $_SERVER['HTTP_REFERER'];
			} else {
				$loc = LINK_ROOT;
			}
		}
		header('Location: ' . $loc);
		die('<script type="text/javascript">window.location.href=\'' . $loc . '\';</script><h1><a href="' . $loc . '">Click here</a></h1>');
	}
	
	/**
	 * Включення *.js файлів до згенерованої сторінки
	 *
	 * @param string $jsPath - шлях до JS бібліотеки
	 */
	public function includeJs($jsPath) {
		$this->includeJS[] = '<script type="text/javascript" src="' . $jsPath . '"></script>';
	}
	
	/**
	 * Додання JS коду в сторінку, без тегів  '<script> ... </script>'
	 *
	 * @param string $jCode
	 */
	public function addJs($jCode) {
		$this->clientJS .= trim($jCode) . RN;
	}
	
	/**
	 * Функція повертає всі скрипти включені в сторінку (як *.js файли так і сам код обрамлений в тег <script>)
	 *
	 * @return string, javascript code
	 */
	public function getClientJs() {
		$ret = join(RN, $this->includeJS);
		$ret .= '<script type="text/javascript">' . RN . '/* <![CDATA[ */' . RN . $this->clientJS . RN . '/* ]]> */' . '</script>';
		return $ret;
	}
	
	/**
	 * Функція додає редактор на сторінку (bbcodes,wysiwyg, тощо)
	 *
	 * @param string $name - назва редактора
	 * @param string $code - код редактора який буде на місці тегу {editor}
	 * @param array $incJS - масив JS файлів які будуть включені в сторінку
	 * @param string $pJS - JS код, який буде включений в сторінку
	 */
	public function addEditor($name, $code, $incJS = array(), $pJS = '') {
		$this->editors[$name]['code'] = $code;
		$this->editors[$name]['js'] = $incJS;
		$this->editors[$name]['pjs'] = $pJS;
	}
	
	/**
	 * Функція повертає код редактора для сторінки і включає в неї всі необхідні скрипти
	 *
	 * @param string $name - назва редактора, якщо не вказано - буде стандартний
	 * @return string - код редактора
	 */
	public function getEditor($name = '') {
		if (! $name) {
			$name = Config::get('editor');
		}
		if (! isset($this->editors[$name])) {
			return;
		}
		if (isset($this->includedEditors[$name]) && $this->includedEditors[$name]) {
			return $this->editors[$name]['code'];
		}
		
		foreach ( $this->editors[$name]['js'] as $j )
			$this->includeJs($j);
		$this->addJs($this->editors[$name]['pjs']);
		$this->includedEditors[$name] = true;
		
		return $this->editors[$name]['code'];
	}
	
	/**
	 * Додавання крону, запуск функції $callback кожні $interval секунд
	 *
	 * @param callback (назва функції) $callback
	 * @param int, інтервал в секундах $interval
	 */
	public function addCronJob($callback, $interval = 86400) {
		$this->cronJobs[$interval][] = $callback;
	}
	
	/**
	 * Виконання крону.
	 *
	 */
	private function cron() {
		$cronData = Cache::get('cronTime');
		$write = false;
		foreach ( $this->cronJobs as $int => $a1c ) {
			$arr[$int] = $cronData[$int];
			
			if (! isset($cronData[$int]) or ((TIME - $cronData[$int]) > $int)) {
				call_user_func($a1c[0]);
				$arr[$int] = TIME;
				$write = true;
			}
		}
		if ($write) {
			Cache::set('cronTime', $arr);
		}
	}
	
	/**
	 * Масив усіх смайликів
	 *
	 * @return array - масив смайликів
	 */
	public function getSmilies() {
		return Cache::callFunction('read_directory', array (ROOT . '/smiles/', 0, 1, 'gif' ));
	}
	
	/**
	 * Генерування посилання на сторінки з шаблону.Стандартні параметри краще не чіпати.
	 *
	 * @param int $mCount - загальна кількість матеріалів (статей, записів, тем , тощо)
	 * @param int $mPerPage - кількість матеріалів на сторінку
	 * @param int $currentPage - поточна сторінка
	 * @param array $hrefArr - масив для створення посилання на сторінку, для формування рядка еквівалентного даному - ?do=forum&thread=5 -потрібен такий масив array('do' => 'forum' , 'thread' => '5')
	 * @param string $pmatname - назва сторінки в рядку ?do=forum&thread=5?$pmatname=N
	 * @param string $template - назва шаблону, зазвичай pages
	 * @return string - згенерований код
	 */
	public function getPagesFromTemplate($model, $mCount, $mPerPage, $currentPage, $hrefArr, $pmatname = 'page', $template = 'pages') {
		$tpl = Template::getInstance();
		$page4left = $page3left = $page2left = $page1left = $page1right = $page2right = $page3right = $page4right = '';
		
		$pages_count = ceil(( int ) $mCount / ( int ) $mPerPage);
		
		if ($pages_count <= 1) {
			return '';
		}
		
		if ($currentPage - 1 > 0)
			$page1left = '<a href="' . Url::formatUrl($model, $hrefArr + array ($pmatname => ($currentPage - 1) ), true) . '">' . ($currentPage - 1) . '</a> ';
		if ($currentPage - 2 > 0)
			$page2left = '<a href="' . Url::formatUrl($model, $hrefArr + array ($pmatname => ($currentPage - 2) ), true) . '">' . ($currentPage - 2) . '</a> ';
		if ($currentPage - 3 > 0)
			$page3left = '<a href="' . Url::formatUrl($model, $hrefArr + array ($pmatname => ($currentPage - 3) ), true) . '">' . ($currentPage - 3) . '</a> ';
		if ($currentPage - 4 > 0)
			$page4left = '<a href="' . Url::formatUrl($model, $hrefArr + array ($pmatname => ($currentPage - 4) ), true) . '">' . ($currentPage - 4) . '</a> ';
		if ($currentPage + 1 <= $pages_count)
			$page1right = '<a href="' . Url::formatUrl($model, $hrefArr + array ($pmatname => ($currentPage + 1) ), true) . '">' . ($currentPage + 1) . '</a> ';
		if ($currentPage + 2 <= $pages_count)
			$page2right = '<a href="' . Url::formatUrl($model, $hrefArr + array ($pmatname => ($currentPage + 2) ), true) . '">' . ($currentPage + 2) . '</a> ';
		if ($currentPage + 3 <= $pages_count)
			$page3right = '<a href="' . Url::formatUrl($model, $hrefArr + array ($pmatname => ($currentPage + 3) ), true) . '">' . ($currentPage + 3) . '</a> ';
		if ($currentPage + 4 <= $pages_count)
			$page4right = '<a href="' . Url::formatUrl($model, $hrefArr + array ($pmatname => ($currentPage + 4) ), true) . '">' . ($currentPage + 4) . '</a> ';
		$pages_e = $page4left . $page3left . $page2left . $page1left . ' <span>' . $currentPage . '</span> ' . $page1right . $page2right . $page3right . $page4right;
		
		$tpl->load($template);
		$tpl->set('{pages}', $pages_e);
		
		if ($currentPage == $pages_count) {
			$tpl->set('[next-link]', '<span>');
			$tpl->set('[/next-link]', '</span>');
			$tpl->set('[last-page]', '<span>');
			$tpl->set('[/last-page]', '</span>');
		} else {
			$tpl->set('[next-link]', '<a href="' . Url::formatUrl($model, $hrefArr + array ($pmatname => ($currentPage + 1) ), true) . '">');
			$tpl->set('[/next-link]', '</a>');
			$tpl->set('[last-page]', '<a href="' . Url::formatUrl($model, $hrefArr + array ($pmatname => $pages_count ), true) . '">');
			$tpl->set('[/last-page]', '</a>');
		}
		if ($currentPage < 2) {
			$tpl->set('[prev-link]', '<span>');
			$tpl->set('[/prev-link]', '</span>');
			$tpl->set('[first-page]', '<span>');
			$tpl->set('[/first-page]', '</span>');
		} else {
			$tpl->set('[prev-link]', '<a href="' . Url::formatUrl($model, $hrefArr + array ($pmatname => ($currentPage - 1) ), true) . '">');
			$tpl->set('[/prev-link]', '</a>');
			$tpl->set('[first-page]', '<a href="' . Url::formatUrl($model, $hrefArr + array ($pmatname => 1 ), true) . '">');
			$tpl->set('[/first-page]', '</a>');
		}
		
		return $tpl->out();
	}
	
	/**
	 * Додає сторінку настройок
	 *
	 * @param unknown_type $name - назва настройок
	 * @param unknown_type $filename - шлях до файлу настройок
	 */
	public function addAdminConfigPage($name, $filename) {
		$this->adminConfigPages[md5($filename . $name)] = array ($name, $filename );
	}
	
	/**
	 * Функція повертає масив рядків інформації на головній сторінці адмінпанелі
	 *
	 * @return  array
	 */
	public function getAdminConfigPageRows() {
		return $this->adminConfigPages;
	}
	
	/**
	 * Провірка чи пусте поле масиву $_POST
	 * В $arrayOfSettings передається асоціативний масив, який складається з назви індексу масиву $_POST і назви поля,
	 * наприклад
	 * checkPostEmpty(array('message' => 'повідомлення'));
	 * Якщо поле $_POST['message'] пусте, то результат роботи фенкції буде таким:
	 * array(
	 * [0] => 'Поле 'повідомлення' не повинно бути порожнім'
	 * )
	 *
	 * @param array $arrayOfSettings
	 * @return array - масив помилок, якщо повертається пустий масив, то помилок нема
	 */
	public function checkPostEmpty($arrayOfSettings) {
		$ret = array ();
		
		foreach ( $arrayOfSettings as $postIndex => $name ) {
			if (empty($_POST[$postIndex])) {
				$ret[] = format(__('Поле \'{%1%}\' не повинно бути порожнім'), $name);
			}
		}
		
		return $ret;
	}
	
	/**
	 * Функція генерує ключові слова на основі даного тексту
	 *
	 * @param string $text
	 * @return
	 */
	public function createKeywords($text) {
		$search = array ("'<script[^>]*?>.*?</script>'si", "'<[\/\!]*?[^<>]*?>'si", "'([\r\n])[\s]+'", "'&(quot|#34);'i", "'&(amp|#38);'i", "'&(lt|#60);'i", "'&(gt|#62);'i", "'&(nbsp|#160);'i", "'&(iexcl|#161);'i", "'&(cent|#162);'i", "'&(pound|#163);'i", "'&(copy|#169);'i", "'&#(\d+);'e" );
		$replace = array (" ", " ", "\\1 ", "\" ", " ", " ", " ", " ", chr(161), chr(162), chr(163), chr(169), "chr(\\1)" );
		$text = preg_replace($search, $replace, strip_tags(stripslashes($text)));
		
		$del_symbols = array (',', '.', ';', ':', '"', '#', '$', '%', '^', '!', '@', '`', '~', '*', '-', '=', '+', '\\', '|', '/', '>', '<', '(', ')', '&', '?', "\t", R, N, '{', '}', '[', ']', "'", '“', '”', '•', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' );
		
		$text = str_replace($del_symbols, ' ', trim($text));
		
		$w_array = explode(' ', $text);
		
		foreach ( $w_array as $val => $key ) {
			if (mb_strlen(trim($key)) > 3) {
				$key_arr[] = trim($key);
			}
		}
		
		if (! isset($key_arr) or ! count($key_arr))
			return '';
		$arr = array_count_values($key_arr);
		arsort($arr);
		$arr = array_keys($arr);
		$total = count($arr);
		$arr = array_slice($arr, 0, 30);
		$metatags = implode(',', $arr);
		return $metatags;
	}
	
	/**
	 * Функція встановлює ключові слова на сторінку
	 *
	 * @param string $keyWords
	 * @return void
	 */
	public function setKeyWords($keyWords) {
		$keyWords = trim($keyWords);
		$aKeyW = explode(',', $keyWords);
		$kw = array ();
		foreach ( $aKeyW as $word ) {
			$kw[] = trim($word);
		}
		array_clean($kw);
		$this->keyWords = array_merge($this->keyWords, $kw);
	}
	
	/**
	 * Функція повертає рядок ключових слів
	 *
	 * @return
	 */
	public function getKeyWords() {
		return join(', ', array_unique($this->keyWords));
	}
	
	public function _echo($string) {
		$this->echo .= $string;
	}
	
	public function addContent($c) {
		$this->content .= $c;
	}
	
	public function getContent() {
		return isset($this->content) ? $this->content : '';
	}
	
	public function addMeta($meta) {
		$this->metadata .= $meta;
	}
	
	public function getMeta() {
		return $this->metadata;
	}
	
	public function getTitle() {
		if (! $this->title) {
			$this->title = Config::get('title');
		}
		return $this->title;
	}
	
	public function is_plugin($pluginClassName) {
		if (class_exists($pluginClassName)) {
			return ( bool ) in_array('Plugin', class_implements($pluginClassName));
		}
		return false;
	}
	
	public function is_module($pluginClassName) {
		if (class_exists($pluginClassName)) {
			return ( bool ) in_array('Module', class_implements($pluginClassName));
		}
		return false;
	}
	
	public function getErrors() {
		return $this->errors;
	}
	public function getInfo() {
		return $this->info;
	}

}